Skip to content

fix(gateway): honor all inference protection modes - #2457

Merged
hidb4ai merged 1 commit into
oceanbase:masterfrom
frf12:codex/gateway-protection-modes
Nov 9, 2026
Merged

hidb4ai merged 1 commit into
oceanbase:masterfrom
frf12:codex/gateway-protection-modes

Conversation

@frf12

@frf12 frf12 commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

Which issue or RFC does this PR close?

Related to #2311. Enforcing-mode image policy remains tracked separately in #2459.

Rationale for this change

Gateway currently cannot use Core with disabled, shadow, or advisory privacy settings. Supporting these modes requires Gateway to honor the deployment mode while Core reports privacy coverage truthfully.

What changes are included in this PR?

  • Core issues context bindings in all four modes after the existing authorization, configured-target, payload-limit, exact-content, and correlation checks. Non-enforcing admission reports coverage.complete=false; enforcing retains request and response privacy enforcement.
  • Gateway requires complete coverage by default. Only trusted Core capability discovery with enforcing=false permits incomplete privacy coverage, consistently for send, retry admission, and release. Schema, phase, binding, deadline, block, and withhold checks remain required.
  • Normalize invalid request JSON, including duplicate keys and non-object roots, to a content-free invalid-request response instead of an uncaught parser error.
  • Document mode behavior in both languages and extend runtime, HTTP, strict external-executor, and real Gateway regression coverage.

OpenAPI, generated models, and Desktop files are unchanged. No new API fields or coverage profiles are introduced. The behavior change is explicit non-enforcing admission for Gateway; existing strict Python SDK and external-executor consumers continue to reject incomplete coverage.

Are there any user-facing changes?

Gateway works with all four configured privacy modes. Disabled skips privacy inspection; shadow and advisory observe requests without blocking and do not inspect responses. These modes do not claim complete privacy protection. Restart Gateway after changing Core's privacy mode to refresh its startup capability discovery. Failed capability discovery does not enable non-enforcing admission.

No database migration is introduced.

How was this change tested?

Head: b6ad802acec1ffd5e030310ecec2175f9987b044, based on master 7fef43d6f (includes the OceanBase scoring test-double fix from #2552).

  • Runtime and atomic scoring regression tests: 48 passed.
  • HTTP authorization, strict external-executor, and Gateway authentication/process tests: 80 passed. Includes incomplete-coverage SDK refusal with zero upstream sends and real Rust Gateway/Python Core/local provider calls across both model routes and all four modes. No external model calls.
  • Rust Core and app unit/integration tests: 145 executed and passed. Four optional localhost Core probes skipped; actual Core/Gateway acceptance is covered by the Python process tests above. Rust doctests could not start because the local temporary toolchain lacks rustdoc.
  • Direct rustfmt check, make check, and git diff --check passed.

The Rust Gateway sources are unchanged by the mainline synchronization; Python regressions, real Gateway process tests, and make check were rerun on the final head. Remote CI is tracked separately on this PR.

AI usage statement

Implemented and reviewed with OpenAI Codex. Validation scope and environment limitations are recorded above; human review is requested before merge.

@hidb4ai hidb4ai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 6bbe031. No blocking issues found. The mode-specific admission behavior is consistent with the documented contract, while authorization, exact prepared-content checks, expiry, and request/response bindings remain enforced.

No database tables or new public operations are introduced; the existing context-check response gains a coverage enum value. Local runtime, authorization, contract, and real Core/Gateway process checks passed. Required CI is still in progress.

@hidb4ai hidb4ai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 6bbe031. No blocking findings. Non-enforcing admission retains context authorization and request/response binding checks, with a distinct coverage profile. No new database tables or public operations; the existing response enum is extended and documented.

Validated the base/head behavior, contracts, and real local Core/Gateway processes. Process tests passed after a startup-timeout retry using a larger startup allowance on this host. Remaining CI checks must pass before merge.

@hidb4ai

hidb4ai commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

please resolve conflict

@frf12
frf12 force-pushed the codex/gateway-protection-modes branch 2 times, most recently from 42dfb56 to a676623 Compare November 5, 2026 18:55
Comment thread desktop/VALIDATION.md
Windows/macOS execution, native credential persistence, installed UI or release readiness.
Historical qualification records retain their identities and evidence.

## Managed observability protocol qualification

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] Restore the historical qualification sections

Deleting these four sections leaves four historical records in desktop/src-tauri/src/connections/compatibility.json with evidence links pointing to nonexistent anchors, removing access to their documented qualification scope. Restore the sections, or preserve the evidence elsewhere and update the catalog links.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

补充精确范围与同源副作用,供按同一处修复。

被删章节 ↔ 悬空记录的准确对应(本 head a676623b,desktop/VALIDATION.md 对 origin/master@69b2d7e2)

按标题生成锚点做集合差,本 PR 删掉 4 个锚点,正好对应 4 条仍在 compatibility.json 里的记录(evidence 字段仍指向这些锚点):

被删锚点 悬空记录 该记录 contractSha256
managed-observability-protocol-qualification sqlite-observability-9f279e4e-v1 44194cfe8ab1…
managed-observability-with-inference-privacy sqlite-observability-a9f6fd36-v1 ad6c1e769089…
server-4568b499-protocol-qualification sqlite-observability-4568b499-v1 de74d8063439…
server-da44b918-protocol-qualification sqlite-observability-da44b918-v1 4d8334f58b97…

要点是第三条:sqlite-observability-4568b499-v1 的摘要 de74d806… 就是 master 当前的 bundled 契约摘要(origin/master:desktop/src-tauri/src/transport/operations.json),也就是说被删掉的不只是历史档案,还包含 master 现役记录的唯一证据段。

同源副作用:整份文件取自旧副本,不只是删章节

  • master 侧 desktop/VALIDATION.md 有 3 处 e4d5e873… / 581cf26b…(clean Desktop 提交与 disposable fixture 提交),本 head 归零;
  • 同时删掉了「native suite 133 tests / 183 frontend / 62 API-Desktop contract」等实测计数,替换为无数字的概述;
  • head 提交历史是 57d79337 chore: merge master into gateway protection modes 与 a676623b merge: sync ... with master 两个 merge,符合「冲突按 ours 整文件解」的特征,与该 merge 正向新增的 Server 56683483 / Server 57d79337 两节并存。

定级:我按 §4 仍定 P2 而非 P1——证据可从 git 历史恢复,没有 CI 门禁覆盖锚点(tests/test_desktop_contract.py 只校验 contractSha256 与 operation 集合,不校验 evidence 锚点),因此不构成阻断。修复应是恢复这四段(而不是改成指向别处的指针),并保留 master 已记录的 probe 提交与计数。

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 0caff3c. The branch now contains the minimal Gateway mode change on master ee3c1ee. desktop/VALIDATION.md and the compatibility catalog are identical to that master commit, so this PR no longer deletes the historical qualification sections or replaces their probe identities and test evidence. This also addresses the additional deletion details in the follow-up comment.

Comment thread desktop/VALIDATION.md Outdated
[compatibility.json](src-tauri/src/connections/compatibility.json) preserves each recorded Server source, normalized OpenAPI contract digest, qualification-wheel digest and operation set. Historical records retain their exact identities and evidence. A record qualifies only its recorded Server source, wheel and contract; records with a different contract digest are disabled in the selector. Saved unavailable selections remain visible until explicitly replaced. Selecting a profile does not extend its recorded operation set or qualify a different Server source. CI builds have their own artifact identities and do not change product qualification.

Statistics additionally require `get_stats` in the selected record's independently qualified operation set.
The observability qualification records are retained alongside the inference-protection records. `sqlite-observability-stats-4568b499-v1` matches the current bundled API contract and independently qualifies all twelve operations, including `get_stats`; `sqlite-observability-4568b499-v1` retains its eleven-operation evidence. Statistics require `get_stats` in the selected record's independently qualified operation set.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 本行「匹配当前 bundled 契约」的断言与本 PR 的摘要前移冲突,照做会选到被选择器禁用的记录

sqlite-observability-stats-4568b499-v1 的 contractSha256 在本 head 仍是 de74d8063439…,而本 PR 改了 openapi/powercontext.yaml(新增 coverage.profile 的 context-bindings.v1 枚举与两处 description),desktop/src-tauri/src/transport/operations.json 的 bundled 摘要已前移到 3ff44a9c7cb0…。复算一致:sha256(LF(openapi/powercontext.yaml@a676623b)) == 3ff44a9c7cb016f4… == operations.json:contractSha256;compatibility.json 54 条记录里与 3ff44a9c… 相等的只有 sqlite-stats-57d79337-merged-v1,sqlite-observability-stats-4568b499-v1 与 bundled 摘要不再相等。

影响:同段第 180 行刚写明「Records with a different contract digest are disabled in the selector」,并要求「explicitly selecting the record whose tested Server source and wheel match the deployment」。按本行文字去选 sqlite-observability-stats-4568b499-v1 的部署方,在选择器里看到的是一条被禁用记录;同一段第 180 行又说 sqlite-stats-57d79337-merged-v1 才「under the current contract digest」,两句话在本 head 相互矛盾。

建议:把本行改为「sqlite-observability-stats-4568b499-v1 保留其在 de74d806… 下的十二操作资格;当前 bundled 摘要由 sqlite-stats-57d79337-merged-v1 承载」,或重新实测后补齐对应记录。若要防同类复发,可对这句加一条断言(operations.json["contractSha256"] 必须等于本段点名的记录),否则下次契约文本再改时同一句会再次失效。

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 0caff3c by removing the OpenAPI/coverage-profile extension and all Desktop changes from this PR. The OpenAPI contract, generated Desktop operations, compatibility catalog, and VALIDATION.md are identical to master ee3c1ee. This PR therefore no longer advances the bundled contract digest or introduces the contradictory current-contract qualification claim. The remaining change is limited to Gateway admission under the four existing privacy modes.

@knqiufan knqiufan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The existing historical-evidence and current-contract qualification findings remain open. The newly added merged qualification also needs its evidence identity corrected.

"evidence": "desktop/VALIDATION.md#server-57d79337-statistics-product-qualification"
},
{
"id": "sqlite-stats-57d79337-merged-v1",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Qualify the Server artifact against the recorded contract

This entry pairs Server commit 57d79337 and its original wheel with contract digest 3ff44a9c…, but that commit's OpenAPI digest is d8cf5d80…. The linked validation describes the original qualification; no separate evidence was found for this merged contract. As written the record makes a qualification claim that the recorded artifact and contract identity do not substantiate. Use a matching built artifact and actual qualification, preserving the historical record.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 0caff3c. The unsupported sqlite-stats-57d79337-merged-v1 qualification added by this PR has been removed along with the other Desktop changes. The compatibility catalog and validation evidence now match master ee3c1ee exactly; this PR makes no new Server artifact or Desktop qualification claim and does not change the OpenAPI contract.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@knqiufan The PR now contains only the Gateway mode handling and its tests/documentation, rebased onto master 7fef43d as b6ad802. Desktop, its qualification catalog/evidence, OpenAPI and generated models are unchanged from master. The mismatched qualification record from the reviewed a676623 was removed. Could you re-review the current head and update the changes-requested verdict if this addresses your concern? CI is rerunning with the merged #2552 scoring-test fix.

@frf12
frf12 force-pushed the codex/gateway-protection-modes branch from a676623 to 0caff3c Compare November 8, 2026 14:42

@hireview001 hireview001 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • CI failed: CI result (failure).
  • CI failed: Upgrade release gate (failure).
  • CI failed: tests (3.12, e2e) (failure).
  • CI failed: Main (failure). Failed steps: tests (3.12, e2e) / Run remaining end-to-end tests; Upgrade release gate / Require the selected parallel acceptance workflow; CI result / Require successful selected checks.

else policy.decision(request.phase, "allow", complete=True)
)
if assessed.decision != "allow" or not assessed.coverage.complete:
if policy.enforcing and (assessed.decision != "allow" or not assessed.coverage.complete):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Handle invalid carriers independently of enforcement mode

With a configured target, malformed or duplicate-key JSON now reaches _validate_prepared() in disabled, shadow, and advisory modes, where uncaught parser exceptions produce HTTP 500. Validate carriers independently of privacy enforcement and translate parsing failures into a controlled invalid-carrier response.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 428172c. Request carrier parsing now translates ValueError/RecursionError at the parse_model_json boundary into InvalidRuntimeRequestError without exposing input content. HTTP regressions cover malformed JSON, duplicate keys, and non-object roots in disabled, shadow, and advisory modes; each returns 422 invalid_request rather than an uncaught server error.

decision="allow",
coverage=assessed.coverage,
reason_codes=assessed.reason_codes,
coverage=assessed.coverage if policy.enforcing else PrivacyCoverage(complete=True),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Distinguish non-enforcing admission from complete privacy coverage

Non-enforcing modes now report complete text-and-tools.v1 coverage for uninspected responses, violating RFC #2086's explicit requirement that disabled or observation-only paths not advertise enforcing coverage. Existing consumers such as external_executor._require_allow() consequently accept those responses as fully checked; distinguish non-enforcing admission explicitly while preserving truthful coverage.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewritten in 428172c. Core now reports coverage.complete=false for every non-enforcing admission, including uninspected responses. Gateway remains strict by default and accepts incomplete coverage only after its existing trusted Core capability discovery explicitly reports enforcing=false. This applies to send, retry, and release while retaining schema, phase, binding, deadline, and block/withhold checks. The Python SDK/external executor remain strict; an HTTP-to-executor regression proves allow+false produces zero upstream sends. No new coverage profile, API fields, OpenAPI changes, or Desktop changes are included.

@frf12
frf12 force-pushed the codex/gateway-protection-modes branch from 0caff3c to 428172c Compare November 9, 2026 04:02
@frf12
frf12 force-pushed the codex/gateway-protection-modes branch from 428172c to b6ad802 Compare November 9, 2026 07:24

@Zxf-xufeng Zxf-xufeng left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@hidb4ai
hidb4ai merged commit cfdb617 into oceanbase:master Nov 9, 2026
40 of 47 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

1.5.1 v1.5.1 release tracking

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants